package ink.ykb.demo.permission.service;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import ink.ykb.demo.config.CodeConstant;
import ink.ykb.demo.config.MessageUtil;
import ink.ykb.demo.config.ServiceException;
import ink.ykb.demo.permission.dao.RoleRuleDao;
import ink.ykb.demo.permission.entity.RoleRule;
import ink.ykb.demo.permission.entity.Rule;

@Service
public class RoleRuleServiceImpl implements RoleRuleService {

  @Autowired
  private MessageUtil messageUtil;
  /**引用自己，用于解决缓存代理失效问题*/
  @Autowired
  private RoleRuleService self;
  @Autowired
  private RoleRuleDao roleRuleDao;
  @Autowired
  private RuleService ruleService;

  
  @Caching(evict = {
      @CacheEvict(cacheNames = {"roleRuleList"}, allEntries=true)
  })
  @Transactional
  @Override
  public void add(RoleRule roleRule) {
    if (roleRule == null) {
      throw new ServiceException(CodeConstant.PARAMS_EMPTY, messageUtil.getMsg(CodeConstant.PARAMS_EMPTY));
    }
    if (roleRule.getRoleId() == null) {
      throw new ServiceException(CodeConstant.PARAMS_EMPTY, messageUtil.getMsg(CodeConstant.PARAMS_EMPTY));
    }
    if (roleRule.getRuleId() == null) {
      throw new ServiceException(CodeConstant.PARAMS_EMPTY, messageUtil.getMsg(CodeConstant.PARAMS_EMPTY));
    }

    RoleRule dbRoleRule =
        roleRuleDao.getRoleRuleAndLock(roleRule.getRoleId(), roleRule.getRuleId());
    if (dbRoleRule != null) {
      throw new ServiceException(CodeConstant.MUS_106, messageUtil.getMsg(CodeConstant.MUS_106));
    }

    roleRule.setCreateTime(new Date());
    roleRuleDao.insert(roleRule);

  }

  @Caching(evict = {
      @CacheEvict(cacheNames = {"roleRule"},key = "#roleRuleId"),
      @CacheEvict(cacheNames = {"roleRuleList"}, allEntries=true)
  })
  @Transactional
  @Override
  public void delete(Long roleRuleId) {
    RoleRule dbRoleRule = roleRuleDao.getRoleRule(roleRuleId);
    if (dbRoleRule == null) {
      throw new ServiceException(CodeConstant.MUS_107, messageUtil.getMsg(CodeConstant.MUS_107));
    }

    roleRuleDao.deleteById(dbRoleRule.getId());
  }

  @Caching(evict = {
      @CacheEvict(cacheNames = {"roleRule"}, allEntries=true),
      @CacheEvict(cacheNames = {"roleRuleList"}, allEntries=true)
  })
  @Transactional
  @Override
  public void deleteByRoleIdAndRuleId(Long roleId, Long ruleId) {

    RoleRule dbRoleRule = roleRuleDao.getRoleRuleAndLock(roleId, ruleId);
    if (dbRoleRule == null) {
      throw new ServiceException(CodeConstant.MUS_107, messageUtil.getMsg(CodeConstant.MUS_107));
    }

    roleRuleDao.deleteById(dbRoleRule.getId());
  }

  @Cacheable(cacheNames = "roleRuleList", key = "'roleRuleList'")
  @Override
  public List<RoleRule> getRoleRuleList() {
    return roleRuleDao.all();
  }

  @Override
  public List<RoleRule> getRoleRuleListByRoleId(Long roleId) {
    List<RoleRule> roleRuleList = self.getRoleRuleList();
    return roleRuleList.stream().filter(rr -> rr.getRoleId().equals(roleId))
        .collect(Collectors.toList());
  }

  @Override
  public List<RoleRule> getRoleRuleListByRuleId(Long ruleId) {
    List<RoleRule> roleRuleList = self.getRoleRuleList();
    return roleRuleList.stream().filter(rr -> rr.getRuleId().equals(ruleId))
        .collect(Collectors.toList());
  }

  @Cacheable(cacheNames = "roleRule", key = "#roleRuleId")
  @Override
  public RoleRule getRoleRule(Long roleRuleId) {
    return roleRuleDao.getRoleRule(roleRuleId);
  }

  @Override
  public RoleRule getRoleRule(Long roleId, Long ruleId) {
    List<RoleRule> roleRuleList = self.getRoleRuleList();
    Optional<RoleRule> opt = roleRuleList.stream()
        .filter(rr -> rr.getRoleId().equals(roleId) && rr.getRuleId().equals(ruleId))
        .findFirst();
    return opt.isPresent() ? opt.get() : null;
  }

  @Override
  public List<Rule> getRuleListByRole(Long roleId) {
    List<RoleRule> roleRuleList = self.getRoleRuleListByRoleId(roleId);

    List<Rule> list = new ArrayList<>();
    roleRuleList.forEach(rr -> {
    	list.add(ruleService.getRule(rr.getRuleId()));
    });

    return list;
  }

  @Caching(evict = {
      @CacheEvict(cacheNames = {"roleRuleList"}, allEntries=true)
  })
  @Transactional
  @Override
  public void addBatchRoleRule(Long roleId, String ruleIds) {
    String[] list = ruleIds.split(",");
    for (String ruleId : list) {
      if (StringUtils.isNotBlank(ruleId)) {
        RoleRule roleRule = new RoleRule();
        roleRule.setRoleId(roleId);
        roleRule.setRuleId(Long.valueOf(ruleId));
        this.add(roleRule);
      }
    }

  }

  @Caching(evict = {
      @CacheEvict(cacheNames = {"roleRule"}, allEntries=true),
      @CacheEvict(cacheNames = {"roleRuleList"}, allEntries=true)
  })
  @Transactional
  @Override
  public void deleteBatchRoleRule(Long roleId, String ruleIds) {
    String[] list = ruleIds.split(",");
    for (String ruleId : list) {
      if (StringUtils.isNotBlank(ruleId)) {
        this.deleteByRoleIdAndRuleId(roleId, Long.valueOf(ruleId));
      }
    }
  }

  @Caching(evict = {
      @CacheEvict(cacheNames = {"roleRule"}, allEntries=true),
      @CacheEvict(cacheNames = {"roleRuleList"}, allEntries=true)
  })
  @Transactional
  @Override
  public void updateBatchRoleRule(Long roleId, String ruleIds) {

    // 此角色原来拥有的权限
    Set<Long> oldRuleIdSet = new HashSet<>();
    List<RoleRule> oldRoleRuleList = this.getRoleRuleListByRoleId(roleId);
    oldRoleRuleList.forEach(rr -> {
      oldRuleIdSet.add(rr.getRuleId());
    });

    // 此角色现在拥有的新权限
    Set<Long> newRuleIdSet = new HashSet<>();

    // 新增的权限
    Set<Long> addRuleIdSet = new HashSet<>();

    List<Rule> ruleList = ruleService.getRuleList();
    String[] ruleIdList = ruleIds.split(",");
    for (String ruleId : ruleIdList) {
      if (StringUtils.isNotBlank(ruleId)) {
        for (Rule rule : ruleList) {
          if (rule.getId().equals(Long.valueOf(ruleId))) {
            newRuleIdSet.add(rule.getId());
            addRuleIdSet.add(rule.getId());
            break;
          }
        }
      }
    }

    // 新增部分，求差集
    addRuleIdSet.removeAll(oldRuleIdSet);

    // 删除部分，求差集
    oldRuleIdSet.removeAll(newRuleIdSet);

    // 新增
    for (Long ruleId : addRuleIdSet) {
      RoleRule roleRule = new RoleRule();
      roleRule.setRoleId(roleId);
      roleRule.setRuleId(ruleId);
      this.add(roleRule);
    }

    // 删除
    for (Long ruleId : oldRuleIdSet) {
      this.deleteByRoleIdAndRuleId(roleId, ruleId);
    }


  }

}
